ThingSpeak Graphs Plots
Contents
ThingSpeak Graphs Plots#
:TODO: hide code by default. This takes editing some json outside visual studio code, if I remember correctly.
First, select your data by venue
# Imports
import ipywidgets as widgets
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from IPython.display import display
# Get the possible data venues
venuekeysfile = "venue-keys.csv"
dfVenueKeys = pd.read_csv(venuekeysfile)
dfVenueKeys = dfVenueKeys.dropna(subset=['channel_id'])
#give user option to select their venue
venueDropdown = widgets.Dropdown(
options=dfVenueKeys['venue_id'],
value=dfVenueKeys['venue_id'][0],
description='Venue ID:',
disabled=False,
)
container = widgets.HBox(children=[venueDropdown])
print(venueDropdown.value)
#Retrieve the venue and begin graphing
dfCollatedDataSet = pd.DataFrame(columns=['timestamp', 'entry_id', 'temperature', 'rh', 'voltage', 'venue_id'])
for index, venueSensorDetails in dfVenueKeys.iterrows():
sensorMacOfSelection = venueSensorDetails['sensor_MAC']
dfTempDataSet = pd.read_csv('deviceData/'+ sensorMacOfSelection + '.csv' )
dfTempDataSet['timestamp'] = pd.to_datetime(dfTempDataSet['timestamp'])
dfTempDataSet['venue_id'] = venueSensorDetails['venue_id']
dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
dfCollatedDataSet['timestamp'] = pd.to_datetime(dfCollatedDataSet['timestamp'])
print('Loading data for venue: ', venueSensorDetails['venue_id'])
print('Check')
dfCollatedDataSet.sample(6)
#dfCollatedDataSet.dtypes
3
Loading data for venue: 3
Loading data for venue: 7
Loading data for venue: 11
Check
/tmp/ipykernel_1835/3984753893.py:38: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
/tmp/ipykernel_1835/3984753893.py:38: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
/tmp/ipykernel_1835/3984753893.py:38: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
| timestamp | entry_id | temperature | rh | voltage | venue_id | |
|---|---|---|---|---|---|---|
| 630 | 2022-08-22 09:04:47+00:00 | 3397 | 21.0 | 60.0 | 40.0 | 3 |
| 7658 | 2022-09-11 09:53:53+00:00 | 10425 | 21.0 | 56.0 | NaN | 3 |
| 2598 | 2022-08-27 16:17:21+00:00 | 5365 | 22.0 | 54.0 | NaN | 3 |
| 4559 | 2022-08-31 17:34:45+00:00 | 7326 | 21.0 | 51.0 | NaN | 3 |
| 8246 | 2022-09-13 12:14:52+00:00 | 11013 | 26.0 | 57.0 | NaN | 3 |
| 8397 | 2022-09-13 22:24:22+00:00 | 11164 | 24.0 | 45.0 | NaN | 3 |
# Assign an empty figure widget with two traces
trace0 = go.Scatter(x=dfCollatedDataSet['temperature'], y = dfCollatedDataSet['timestamp'], mode='lines', hoverinfo='all', name='temperature')
#trace1 = go.Scatter(x=dfCollatedDataSet['rh'], mode='lines', hoverinfo='all', name='relative humidity')
importantValues = []
importantValues.append({'type': 'line',
'xref': 'x',
'yref': 'y',
'x0': dfCollatedDataSet['timestamp'].min(),
'y0': 16,
'x1': dfCollatedDataSet['timestamp'].max(),
'y1': 16,
'line_color': 'red',
'line_dash': 'dash',
'layer':'below'})
annotationsToDraw = []
annotationsToDraw.append({'text': 'Legal indoor temperature for children',
'x': dfCollatedDataSet['timestamp'].max(),
'y': 16})
g = go.FigureWidget(data=[trace0],
layout = go.Layout(
title=dict(
text='Temperature for Venue: ' + str(venueDropdown.value)
),
shapes=importantValues,
annotations=annotationsToDraw
#barmode='lines'
))
print("Job Done")
Job Done
filter_list = [i for i in dfCollatedDataSet['venue_id'] == venueDropdown.value]
temp_df = dfCollatedDataSet[filter_list]
y1 = temp_df['temperature']
x1 = temp_df['timestamp']
#y2 = temp_df['rh']
#x2 = temp_df['dep_delay']
with g.batch_update():
g.data[0].y = y1
g.data[0].x = x1
#g.data[1].y = y2
#g.layout.barmode = 'overlay'
g.layout.xaxis.title = 'Time'
g.layout.yaxis.title = 'Temperature'
g.layout.title = "Temperature for Venue = " + str(venueDropdown.value)
def response(change):
filter_list = [i for i in dfCollatedDataSet['venue_id'] == venueDropdown.value]
temp_df = dfCollatedDataSet[filter_list]
y1 = temp_df['temperature']
x1 = temp_df['timestamp']
#y2 = temp_df['rh']
#x2 = temp_df['dep_delay']
with g.batch_update():
g.data[0].y = y1
g.data[0].x = x1
#g.data[1].y = y2
#g.layout.barmode = 'overlay'
g.layout.xaxis.title = 'Time'
g.layout.yaxis.title = 'Value'
g.layout.title = dict(text= 'Temperature for Venue = ' + str(venueDropdown.value))
# g.add_trace(go.Scatter(x=temp_df['timestamp'], y = 16))
# g.add_hline(y=16,
# x0=dfCollatedDataSet['timestamp'].min(),
# x1=dfCollatedDataSet['timestamp'].max(),
# line_color="red")
venueDropdown.observe(response, names="value")
graphA = widgets.VBox([container, g])
display(graphA)
Collate
# Imports
import ipywidgets as widgets
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from IPython.display import display
# Get the possible data venues
venuekeysfile = "venue-keys.csv"
dfVenueKeys = pd.read_csv(venuekeysfile)
dfVenueKeys = dfVenueKeys.dropna(subset=['channel_id'])
#give user option to select their venue
venueDropdown = widgets.Dropdown(
options=dfVenueKeys['venue_id'],
value=dfVenueKeys['venue_id'][0],
description='Venue ID:',
disabled=False,
)
container = widgets.HBox(children=[venueDropdown])
print(venueDropdown.value)
#Retrieve the venue and begin graphing
dfCollatedDataSet = pd.DataFrame(columns=['timestamp', 'entry_id', 'temperature', 'rh', 'voltage', 'venue_id'])
for index, venueSensorDetails in dfVenueKeys.iterrows():
sensorMacOfSelection = venueSensorDetails['sensor_MAC']
dfTempDataSet = pd.read_csv('deviceData/'+ sensorMacOfSelection + '.csv' )
dfTempDataSet['timestamp'] = pd.to_datetime(dfTempDataSet['timestamp'])
dfTempDataSet['venue_id'] = venueSensorDetails['venue_id']
dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
dfCollatedDataSet['timestamp'] = pd.to_datetime(dfCollatedDataSet['timestamp'])
print('Loading data for venue: ', venueSensorDetails['venue_id'])
print('Check')
dfCollatedDataSet.sample(6)
#dfCollatedDataSet.dtypes
# Assign an empty figure widget with two traces
trace0 = go.Scatter(x=dfCollatedDataSet['temperature'], y = dfCollatedDataSet['timestamp'], mode='lines', hoverinfo='all', name='temperature')
#trace1 = go.Scatter(x=dfCollatedDataSet['rh'], mode='lines', hoverinfo='all', name='relative humidity')
importantValues = []
importantValues.append({'type': 'line',
'xref': 'x',
'yref': 'y',
'x0': dfCollatedDataSet['timestamp'].min(),
'y0': 16,
'x1': dfCollatedDataSet['timestamp'].max(),
'y1': 16,
'line_color': 'red',
'line_dash': 'dash',
'layer':'below'})
annotationsToDraw = []
annotationsToDraw.append({'text': 'Legal indoor temperature for children',
'x': dfCollatedDataSet['timestamp'].max(),
'y': 16})
g = go.FigureWidget(data=[trace0],
layout = go.Layout(
title=dict(
text='Temperature for Venue: ' + str(venueDropdown.value)
),
shapes=importantValues,
annotations=annotationsToDraw
#barmode='lines'
))
print("Job Done")
filter_list = [i for i in dfCollatedDataSet['venue_id'] == venueDropdown.value]
temp_df = dfCollatedDataSet[filter_list]
y1 = temp_df['temperature']
x1 = temp_df['timestamp']
#y2 = temp_df['rh']
#x2 = temp_df['dep_delay']
with g.batch_update():
g.data[0].y = y1
g.data[0].x = x1
#g.data[1].y = y2
#g.layout.barmode = 'overlay'
g.layout.xaxis.title = 'Time'
g.layout.yaxis.title = 'Temperature'
g.layout.title = "Temperature for Venue = " + str(venueDropdown.value)
def response(change):
filter_list = [i for i in dfCollatedDataSet['venue_id'] == venueDropdown.value]
temp_df = dfCollatedDataSet[filter_list]
y1 = temp_df['temperature']
x1 = temp_df['timestamp']
#y2 = temp_df['rh']
#x2 = temp_df['dep_delay']
with g.batch_update():
g.data[0].y = y1
g.data[0].x = x1
#g.data[1].y = y2
#g.layout.barmode = 'overlay'
g.layout.xaxis.title = 'Time'
g.layout.yaxis.title = 'Value'
g.layout.title = dict(text= 'Temperature for Venue = ' + str(venueDropdown.value))
# g.add_trace(go.Scatter(x=temp_df['timestamp'], y = 16))
# g.add_hline(y=16,
# x0=dfCollatedDataSet['timestamp'].min(),
# x1=dfCollatedDataSet['timestamp'].max(),
# line_color="red")
venueDropdown.observe(response, names="value")
graphA = widgets.VBox([container, g])
display(graphA)
3
Loading data for venue: 3
Loading data for venue: 7
Loading data for venue: 11
Check
/tmp/ipykernel_1835/1996588037.py:38: FutureWarning:
The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
/tmp/ipykernel_1835/1996588037.py:38: FutureWarning:
The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
/tmp/ipykernel_1835/1996588037.py:38: FutureWarning:
The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
Job Done
import plotly.express as px
import plotly.graph_objects as go
# filename = "thingspeak-feed"
# dfthingspeak = pd.read_csv(filename + ".csv")
# dfthingspeak["timestamp"] = pd.to_datetime(dfthingspeak['created_at'])
fig = px.line(dfCollatedDataSet, x='timestamp', y='temperature', range_x=['','2022-09-09'], title="Temperature in a worship space: " + str(venueDropdown.value))
fig = px.line(dfCollatedDataSet, x= 'timestamp', y=dfCollatedDataSet.columns[2:4], title="Temperature in a worship space: " + str(venueDropdown.value))
fig.add_hline(y=16)
fig.show()
Towards a calibration plot#
Simple demonstration of data from two data frames on the same plot - with the wrinkle that one frame is from a lascar logger. We will be roughly exploring the calibration of the RH sensors by running batches of 10 DHT22s alongside a few Lascars over an RH range and showing groups the results, so they can judge how much to trust the data.
Lascars aren’t configurable for what they export. I’ve removed a Unicode character this couldn’t deal with (degree symbol) and used Excel to change the data format. These things should be fixable in code, but we won’t use Lascars enough for that to be a priority task. Any processing we need to do on Thingspeak feeds is a priority, though.
I don’t really understand the interaction between px.line and add_scatter - the difference can get in the way. This way of using plotly and dropping down to graph_objects might be misguided.
# Using plotly.express
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
dfthingspeak = pd.read_csv("thingspeak-feed.csv")
dfthingspeak["timestamp"] = pd.to_datetime(dfthingspeak['created_at'])
dflascar = pd.read_csv("lascar-data.csv")
dflascar['timestamp'] = pd.to_datetime(dflascar['Time'])
# fig = px.line(dfthingspeak, x='timestamp', y='field2', range_x=['2021-11-21','2022-04-07'],range_y=[35,85], title="Comparing RH as measured by different devices")
fig = px.line(dfthingspeak, x='timestamp', range_x=['2021-11-21','2022-04-07'],range_y=[35,85], title="Comparing RH in a worship space as measured by different devices side by side")
fig.add_scatter(x = dfthingspeak['timestamp'], y = dfthingspeak['field2'], name = 'thingspeak')
fig.add_scatter(x = dflascar['timestamp'], y = dflascar['RH'], name = 'lascar')
fig.show()
Showing when space is in use.#
Vertical lines are useful for the start and end time of events. It would be better rendered as a separate background shading when the space is occupied.
Perhaps we can set up a worksheet where they put in their usual weekly schedule with a descriptive short string to render these. We could use diary export, but if their diary doesn’t have a busy/free option, there’s too much risk of personal data being in there, and there could be too many diary systems to deal with.
:TODO: It would be helpful if there were a dropdown control for choosing to view a day or a week, and then which specific day or week. That sort of control could be used to choose the group and venue, as well, so we’re only producing one master book for everyone.
# Using plotly.express
import plotly.express as px
import pandas as pd
df = pd.read_csv("thingspeak-feed.csv")
df["timestamp"] = pd.to_datetime(df['created_at'])
#animation_frame and animation_group should make it possible to add a range slider??
fig = px.line(df, x='timestamp', y='field1', range_x=['2021-12-24','2021-12-26'],range_y=[0,20], title="Midnight mass and Christmas morning services in a worship space.")
fig.add_vline(x='2021-12-24 23:00')
fig.add_vline(x='2021-12-25 00:00')
fig.add_vline(x='2021-12-25 10:00')
fig.add_vline(x='2021-12-25 11:30')
fig.show()